<script setup lang="ts" name="SystemMenuForm">
import { storeToRefs } from 'pinia'
import { useAppStoreWithOut } from '@/store/modules/app'
import { getIntDictOptions, getBoolDictOptions } from '@/utils/dict'
import { DICT_TYPE } from '@/enums/dictEnums'
import { MenuApi, MenuType } from '@/api/system/menu/index'
import { ScenesType, CommonStatusEnum } from '@/enums/commonEnums'
import { SystemMenuTypeEnum } from '@/enums/systemEnums'
import { handleTree, findNodeById, treeFormat } from '@/utils/tree'
const appStore = useAppStoreWithOut()
const { systemConfig } = storeToRefs(appStore)

const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗

const visible = ref(false) // 弹窗的是否展示
const title = ref('') // 弹窗的标题
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用
const formType = ref('') // 表单的类型：create - 新增；update - 修改
const formData = ref({
  id: undefined,
  parentId: 0,
  title: '',
  icon: '',
  component: '',
  path: '',
  visible: true,
  sort: 0,
  name: '',
  permit: '',
  transitionName: undefined,
  keepAlive: true,
  isFixed: false,
  type: SystemMenuTypeEnum.MENU,
  badge: '',
  dot: false,
  status: CommonStatusEnum.ENABLE,
  remark: ''
})
const formRules = reactive({
  title: [{ required: true, message: t('sys.menu.rules', 'name'), trigger: 'blur' }],
  component: [{ required: true, message: t('sys.menu.rules', 'emptyComponent'), trigger: 'blur' }],
  path: [{ required: true, message: t('sys.menu.rules', 'path'), trigger: 'blur' }],
  name: [{ required: true, message: t('sys.menu.rules', 'emptyRouteName'), trigger: 'blur' }],
  permit: [{ required: true, message: t('sys.menu.rules', 'permission'), trigger: 'blur' }],
  icon: [{ required: true, message: t('common.icon.rules', 'select'), trigger: 'blur' }]
})
const formRef = ref() // 表单 Ref
const currentParentMenuType = ref(1) // 上级菜单的菜单类型

/** 打开弹窗 */
const open = async (type: string, id?: number, parentId?: number) => {
  visible.value = true
  title.value = t('action', type)
  formType.value = type
  // 获得菜单列表
  await getTree()
  resetForm()
  if (parentId){
    formData.value.parentId = parentId
    const menu = findNodeById(menuTree.value, parentId)
    currentParentMenuType.value = menu.type
  }
  // 修改时，设置数据
  if (id) {
    formLoading.value = true
    try {
      formData.value = await MenuApi.detail(id)
      setParentMenuDisabledType()
    } finally {
      formLoading.value = false
    }
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

/** 提交表单 */
const emit = defineEmits(['success']) // 定义 success 事件，用于操作成功后的回调
const submitForm = async () => {
  // 校验表单
  if (!formRef) return
  const valid = await formRef.value.validate()
  if (!valid) return
  // 提交请求
  formLoading.value = true
  try {
    const data = formData.value as unknown as MenuType
    if (formType.value === 'create') {
      await MenuApi.create(data)
      message.success(t('message', 'createSuccess'))
    } else {
      await MenuApi.update(data)
      message.success(t('message', 'updateSuccess'))
    }
    visible.value = false
    // 发送操作成功的事件
    emit('success')
  } finally {
    formLoading.value = false
  }
}

/** 获取下拉框[上级菜单]的数据  */
const menuTree = ref<Tree[]>([]) // 树形结构
const getTree = async () => {
  menuTree.value = []
  const res = await MenuApi.simple()
  let menu: Tree = { id: 0, title: t('sys.menu', 'all'), type: SystemMenuTypeEnum.DIR, disabled: false, children: [] }
  menu.children = handleTree(res)
  menuTree.value.push(menu)
  treeFormat(menuTree.value, 'title', 'id', () => {
    return false
  })
}

// 菜单类型切换事件
const menuTypeChange = () => {
  formData.value = {
    id: formData.value.id,
    parentId: formData.value.parentId,
    title: formData.value.title,
    icon: '',
    component: '',
    path: '',
    visible: true,
    sort: formData.value.sort,
    name: '',
    permit: '',
    transitionName: undefined,
    keepAlive: formData.value.type === SystemMenuTypeEnum.MENU ? true : false,
    isFixed: false,
    type: formData.value.type,
    badge: '',
    dot: false,
    status: formData.value.status,
    remark: formData.value.remark
  }
  formRef.value?.resetFields()
  setParentMenuDisabledType()
}

// 上级菜单切换事件
const parentMenuChange = (v) => {
  const menu = findNodeById(menuTree.value, v)
  currentParentMenuType.value = menu.type
}

// 设置菜单类型的禁用状态
const isDisabledType = (v) => {
  if (currentParentMenuType.value === SystemMenuTypeEnum.DIR) {
    if (v === SystemMenuTypeEnum.BUTTON) {
      return true
    } else {
      return false
    }
  } else {
    if (v === SystemMenuTypeEnum.DIR) {
      return true
    } else {
      return false
    }
  }
}

// 设置上级菜单的禁用状态
const setParentMenuDisabledType = () => {
  treeFormat(menuTree.value, 'title', 'id', (item) => {
    if (formData.value.type === SystemMenuTypeEnum.BUTTON) {
      if (item.type === SystemMenuTypeEnum.DIR) {
        return true
      } else {
        return false
      }
    } else {
      return false
    }
  })
}

/** 重置表单 */
const resetForm = () => {
  formData.value = {
    id: undefined,
    parentId: 0,
    title: '',
    icon: '',
    component: '',
    path: '',
    visible: true,
    sort: 0,
    name: '',
    permit: '',
    transitionName: undefined,
    keepAlive: true,
    isFixed: false,
    type: SystemMenuTypeEnum.MENU,
    badge: '',
    dot: false,
    status: CommonStatusEnum.ENABLE,
    remark: ''
  }
  formRef.value?.resetFields()
  setParentMenuDisabledType()
}
</script>

<template>
  <Dialog v-model="visible" :title="title" width="960px">
    <el-form ref="formRef" v-loading="formLoading && systemConfig.loadingType === 'module'" :model="formData" :rules="formRules" label-width="90px">
      <div class="el-form-group">
        <ElFormItem :label="t('sys.menu', 'parent')">
          <el-tree-select ref="menuRef" v-model="formData.parentId" :data="menuTree" :default-expand-all="true" filterable node-key="id" :props="{label: 'title'}" check-strictly :placeholder="t('sys.menu.rules', 'parent')" @change="parentMenuChange" />
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'type')">
          <el-radio-group v-model="formData.type" class="radio-button" @change="menuTypeChange">
            <el-radio-button v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_MENU_TYPE)" :key="dict.label" :disabled="isDisabledType(dict.value)" :value="dict.value">
              {{ dict.label }}
            </el-radio-button>
          </el-radio-group>
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'name')" prop="title">
          <el-input v-model="formData.title" clearable :placeholder="t('sys.menu.rules', 'name')" />
        </ElFormItem>
      </div>
      <el-form-item v-if="formData.type === SystemMenuTypeEnum.MENU" class="mt-6px" :label="t('sys.menu', 'component')" prop="component">
        <el-input v-model="formData.component" clearable :placeholder="t('sys.menu.rules', 'component')" />
      </el-form-item>
      <el-form-item v-if="formData.type === SystemMenuTypeEnum.MENU" :label="t('sys.menu', 'path')" prop="path">
        <template #label>
          <Tooltip :message="t('sys.menu.tips', 'path')" :title="t('sys.menu', 'path')" />
        </template>
        <el-input v-model="formData.path" clearable :placeholder="t('sys.menu.rules', 'path')" />
      </el-form-item>
      <el-form-item v-if="formData.type === SystemMenuTypeEnum.MENU" :label="t('sys.menu', 'routeName')" prop="name">
        <template #label>
          <Tooltip :message="t('sys.menu.tips', 'routeName')" :title="t('sys.menu', 'routeName')" />
        </template>
        <el-input v-model="formData.name" clearable :placeholder="t('sys.menu.rules', 'routeName')" />
      </el-form-item>
      <el-form-item v-if="formData.type !== SystemMenuTypeEnum.DIR" :label="t('sys.menu', 'permission')" prop="permit">
        <template #label>
          <Tooltip :message="t('sys.menu.tips', 'permission')" :title="t('sys.menu', 'permission')" />
        </template>
        <el-input v-model="formData.permit" clearable :placeholder="t('sys.menu.rules', 'permission')" />
      </el-form-item>
      <div v-if="formData.type === SystemMenuTypeEnum.MENU" class="el-form-group mt-6px">
        <ElFormItem :label="t('sys.menu', 'keepAlive')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'keepAlive')" :title="t('sys.menu', 'keepAlive')" />
          </template>
          <el-radio-group v-model="formData.keepAlive" class="radio-button">
            <el-radio-button v-for="(item, index) in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="index" :value="item.value" border>
              {{ item.label }}
            </el-radio-button>
          </el-radio-group>
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'fixed')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'fixed')" :title="t('sys.menu', 'fixed')" />
          </template>
          <el-radio-group v-model="formData.isFixed" class="radio-button">
            <el-radio-button v-for="(item, index) in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="index" :value="item.value" border>
              {{ item.label }}
            </el-radio-button>
          </el-radio-group>
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'transitionName')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'transitionName')" :title="t('sys.menu', 'transitionName')" />
          </template>
          <el-select v-model="formData.transitionName" clearable :placeholder="t('sys.menu.rules', 'transitionName')">
            <el-option v-for="item in ScenesType" :key="item.value" :label="item.label" :value="item.value" />
          </el-select>
        </ElFormItem>
      </div>
      <div v-if="formData.type !== SystemMenuTypeEnum.BUTTON" class="el-form-group mt-6px">
        <ElFormItem :label="t('sys.menu', 'visible')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'visible')" :title="t('sys.menu', 'visible')" />
          </template>
          <el-radio-group v-model="formData.visible" class="radio-button">
            <el-radio-button v-for="(item, index) in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="index" :value="item.value" border>
              {{ item.label }}
            </el-radio-button>
          </el-radio-group>
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'dot')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'dot')" :title="t('sys.menu', 'dot')" />
          </template>
          <el-radio-group v-model="formData.dot" class="radio-button">
            <el-radio-button v-for="(item, index) in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="index" :value="item.value" border>
              {{ item.label }}
            </el-radio-button>
          </el-radio-group>
        </ElFormItem>
        <ElFormItem :label="t('sys.menu', 'badge')">
          <template #label>
            <Tooltip :message="t('sys.menu.tips', 'badge')" :title="t('sys.menu', 'badge')" />
          </template>
          <el-input v-model="formData.badge" clearable :placeholder="t('sys.menu.rules', 'badge')" />
        </ElFormItem>
      </div>
      <div class="el-form-group mt-6px mb-6px">
        <ElFormItem v-if="formData.type !== SystemMenuTypeEnum.BUTTON" :label="t('common.icon', 'title')" prop="icon">
          <InputIconPicker v-model:icon="formData.icon" />
        </ElFormItem>
        <el-form-item :label="t('common', 'status')" prop="status">
          <el-radio-group v-model="formData.status" class="radio-button">
            <el-radio-button v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" :key="dict.value" :value="dict.value">
              {{ dict.label }}
            </el-radio-button>
          </el-radio-group>
        </el-form-item>
        <ElFormItem :label="t('common', 'sort')">
          <el-input-number v-model="formData.sort" clearable />
        </ElFormItem>
        <el-form-item v-if="formData.type === SystemMenuTypeEnum.BUTTON" />
      </div>
      <el-form-item :label="t('common', 'remark')" prop="remark">
        <el-input v-model="formData.remark" clearable :placeholder="t('common.rules', 'remark')" type="textarea" />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="visible = false">{{ t('action', 'cancel') }}</el-button>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">{{ t('action', 'confirm') }}</el-button>
    </template>
  </Dialog>
</template>

<style scoped lang="scss">
.el-form{
  margin-right: -6px;
}

.el-form-group {
  display: flex;
  flex: 1;

  .el-form-item {
    flex: 1;
    margin: 0;
  }

  .el-form-item+.el-form-item {
    margin: 0;
  }
}

.el-form-group + .el-form-item{
  margin-top: 6px;
}
</style>
